#include "CNetworkManager.h"

#include "CStateRoom.h"
#include "CChatBox.h"
#include "CNetworkIO.h"
#include "COverlord.h"

#include <windows.h>

CNetworkManager::CNetworkManager(CGameManager* mgr, stringc ip, u16 port) : mgr(mgr)
{
  peer = RakNetworkFactory::GetRakPeerInterface();
  // Connect to the game server

  client = RakNetworkFactory::GetRakPeerInterface();

  client->Startup(1,30,&SocketDescriptor(), 1);

  cout << "Connecting to Server IP: " << ip.c_str() << " Port: " << port << endl;
  client->Connect(ip.c_str(), port, 0,0);

  toServer = true;
}

CNetworkManager::~CNetworkManager()
{
  RakNetworkFactory::DestroyRakPeerInterface(peer);

  client->Shutdown(1000);
  Sleep(1000); //! TODO: Not a good method
  RakNetworkFactory::DestroyRakPeerInterface(client);
}

void CNetworkManager::createRoom()
{
  isHost = true;

  std::cout << "Creating a server." << std::endl;
  peer->Startup(1, 30, &SocketDescriptor(gamePort,0), 1);

  // We need to let the server accept incoming connections from the clients
  peer->SetMaximumIncomingConnections(1);

  stringw caption(GAME_TITLE);
  caption += " - Game Host";
  mgr->getDevice()->setWindowCaption(caption.c_str());

}

void CNetworkManager::joinRoom(stringc ip)
{
  isHost = false;

  std::cout << "Joining game room of address :\"" << ip.c_str() << "\"" << std::endl;
  peer->Startup(1,30,&SocketDescriptor(), 1);

  peer->Connect(ip.c_str(), gamePort, 0,0);

  stringw caption(GAME_TITLE);
  caption += " - Game Client";
  mgr->getDevice()->setWindowCaption(caption.c_str());
}

void CNetworkManager::leaveRoom()
{
  peer->Shutdown( 1000 );
}

void CNetworkManager::readPacket()
{
  // Packet from server
  packet = client->Receive();
  while (packet)
  {
    if (packet->data[0] == ID_LON_CHAT)
    {
      readChat(true);
    }
    else
    {
      mgr->getState()->OnServerPacketReceived(packet);
    }

    client->DeallocatePacket(packet);
    packet = client->Receive();
  }

  // Packet from other client
  packet = peer->Receive();
  while (packet)
  {
    if (packet->data[0] == ID_LON_CHAT)
    {
      readChat(true);
    }
    else
    {
      mgr->getState()->OnClientPacketReceived(packet);
    }

    peer->DeallocatePacket(packet);
    packet = peer->Receive();
  }

}

void CNetworkManager::sendPacket(BitStream* bitStream, bool toServer)
{
  if (toServer)
    client->Send(bitStream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
  else
    peer->Send(bitStream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
}

void CNetworkManager::sendChat()
{

  // Create new bitstream for packet
  BitStream *bs = new BitStream();

  stringw chat = mgr->getPlayer()->getName();
  chat += " : ";
  chat += mgr->getChatBox()->getText();

  // Write the message ID
  msgId = ID_LON_CHAT;
  bs->Write(msgId);

  CNetworkIO::writeWcs(*bs, chat.c_str());

  // Send the packet
  if (toServer)
  {
    // Send the packet
    client->Send(bs, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
  }
  else
  {
    peer->Send(bs, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true);

    if (isHost)
      // Add the text to the GUI
      mgr->getChatBox()->addText(chat.c_str());
  }


}

void CNetworkManager::readChat(bool fromServer)
{
  BitStream bs(packet->data, packet->length, false);

  bs.Read(msgId);
  stringw text = CNetworkIO::readWcs(bs);
  mgr->getChatBox()->addText(text.c_str(), fromServer);
}

void CNetworkManager::setToServer(bool toServer)
{
  this->toServer = toServer;
}

bool CNetworkManager::IsHost()
{
  return isHost;
}

void CNetworkManager::setGamePort(u16 port)
{
  this->gamePort = port;
}
